package com.hmall.gateway.routers;


import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {
    //引入写入路由配置工具
    private final RouteDefinitionWriter routeDefinitionWriter;
    //引入nacos配置管理器
    private final NacosConfigManager nacosConfigManager;

    private final String dataId = "gateway-routes.json";

    private final String group = "DEFAULT_GROUP";

    private final Set<String> routeIds = new HashSet<>();
    @PostConstruct  //在注入类之后 初始化方法
    private void initRouteConfigListener() throws NacosException {
        //初始化路由监听器
        //1.项目启动时先拉去一下配置 监听配置变化
        String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {
            @Override
            public Executor getExecutor() { //定义一个线程池 用来异步执行监听器
                return null;
            }

            @Override
            public void receiveConfigInfo(String configInfo) {
                //2.监听到配置变革 重新加载路由配置
                updateConfigInfo(configInfo);

            }
        });
        //3.第一次获取配置 需要加载到路由表中
        updateConfigInfo(configInfo);
    }
    public void updateConfigInfo(String configInfo) {
        log.debug("监听到路由配置更新，重新加载路由配置"+configInfo);
        //1.解析配置文件 转为RouteDefinition对象
        List<RouteDefinition> definitionList = JSONUtil.toList(configInfo, RouteDefinition.class);
        //2.更新路由配置
        //2.1先删除旧的路由配置
        for (String routeId : routeIds) {
            try {
                routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
            } catch (Exception e) {
                log.error("删除路由配置失败", e);
            }
        }
        routeIds.clear();
        for (RouteDefinition routeDefinition : definitionList) {
            //3.1更新路由配置
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            //3.2记录路由Id 方便下一次更新删除
            routeIds.add(routeDefinition.getId());
        }

    }

}
